#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <semaphore.h>
#include <pthread.h>
#include <ctime>

template <typename T>
class RingQueue
{
private:
void p(sem_t &s)
{
    sem_wait(&s);
}

void v(sem_t &s)
{
    sem_post(&s);
}

public:

RingQueue(int max)
:_ring_queue(max = 5)
,_max_cap(max)
, _p_step(0)
,_c_step(0)
{
    sem_init(&_data_sem,0,0);
    sem_init(&_space_sem,0,_max_cap);

    pthread_mutex_init(&_p_mutex,nullptr);
    pthread_mutex_init(&_c_mutex,nullptr);
}

void Push(const T &in)
{
    p(_space_sem);
    pthread_mutex_lock(&_p_mutex);

    _ring_queue[_p_step] = in;
    _p_step++;
    _p_step %= _max_cap;

    pthread_mutex_unlock(&_p_mutex);
    v(_data_sem);
}

void Pop(T *out)
{
    p(_data_sem);
    pthread_mutex_lock(&_c_mutex);

    *out = _ring_queue[_c_step];
    _c_step++;
    _c_step %= _max_cap;

    pthread_mutex_unlock(&_c_mutex);
    v(_space_sem);
}


~RingQueue()
{
    sem_destroy(&_data_sem);
    sem_destroy(&_space_sem);

    pthread_mutex_destroy(&_p_mutex);
    pthread_mutex_destroy(&_c_mutex);
}
private:
std::vector<T> _ring_queue;
int _max_cap;

int _p_step;
int _c_step;

sem_t _data_sem;
sem_t _space_sem;

pthread_mutex_t _p_mutex;
pthread_mutex_t _c_mutex;
};